﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using JeanFish.Conversion;

namespace JeanFish.UnitTest.Conversion
{
    [TestClass]
    public class JSONTest
    {
        const string catetory = "JSON";
        string[] testJsons;
        [TestMethod]
        [TestCategory(catetory)]
        [ExpectedException(typeof(Exception))]
        public void TestParseNullJson()
        {
            testJsons = new string[] { " \t fd  f ]" };
            foreach (var jsonStr in testJsons)
            {
                var json = JSON.Parse(jsonStr);
                Assert.IsNull(json);
            }
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseEmptyObject()
        {
            testJsons = new string[] { "  {}", "{  \t  }  " };
            foreach (var jsonStr in testJsons)
            {
                var json = JSON.Parse(jsonStr);
                Assert.IsTrue(json is JSONObject);
                var jsonObj = json as JSONObject;
                Assert.IsTrue(jsonObj != null && jsonObj.Count == 0);
            }
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseEmptyArray()
        {
            testJsons = new string[] { " \r []", "[  \t  ]  " };
            foreach (var jsonStr in testJsons)
            {
                var json = JSON.Parse(jsonStr);
                Assert.IsTrue(json is JSONArray);
                var jsonArr = json as JSONArray;
                Assert.IsTrue(jsonArr != null && jsonArr.Count == 0);
            }
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseEmptyObjectsInArray()
        {
            string jsonStr = "[{},{},{},{}]";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONArray);
            var jsonArr = json as JSONArray;
            Assert.IsNotNull(jsonArr);
            Assert.AreEqual(4, jsonArr.Count);
            Assert.IsTrue(jsonArr[0] is JSONObject);
            var jsonObj = jsonArr[0] as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 0);

        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseNumber()
        {
            string jsonStr = "[-1.01e+1,0.01,123.98e-1,0.01e2]";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONArray);
            var jsonArr = json as JSONArray;
            Assert.IsTrue(jsonArr != null && jsonArr.Count == 4);
            Assert.IsTrue(jsonArr[0] is Double);
            double jsonNumber = (double)jsonArr[0];
            Assert.AreEqual(-10.1, jsonNumber);

            Assert.IsTrue(jsonArr[1] is Double);
            jsonNumber = (double)jsonArr[1];
            Assert.AreEqual(0.01, jsonNumber);

            Assert.IsTrue(jsonArr[2] is Double);
            jsonNumber = (double)jsonArr[2];
            Assert.AreEqual(12.398, jsonNumber);

            Assert.IsTrue(jsonArr[3] is Double);
            jsonNumber = (double)jsonArr[3];
            Assert.AreEqual(1, jsonNumber);
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseString()
        {
            string jsonStr = @"[""\t"",""\u8896"",""is \""123\"" a string?\r\nYes, it is.""]";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONArray);
            var jsonArr = json as JSONArray;
            Assert.IsTrue(jsonArr != null && jsonArr.Count == 3);
            Assert.IsTrue(jsonArr[0] is string);
            string jsonString = (string)jsonArr[0];
            Assert.AreEqual("\t", jsonString);

            Assert.IsTrue(jsonArr[0] is string);
            jsonString = (string)jsonArr[1];
            Assert.AreEqual("袖", jsonString);

            Assert.IsTrue(jsonArr[0] is string);
            jsonString = (string)jsonArr[2];
            Assert.AreEqual("is \"123\" a string?\r\nYes, it is.", jsonString);
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseTrueFalseNull()
        {
            string jsonStr = @"[true,false,null]";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONArray);
            var jsonArr = json as JSONArray;
            Assert.IsTrue(jsonArr != null && jsonArr.Count == 3);
            Assert.IsTrue(jsonArr[0] is bool);
            bool jsonBoolean = (bool)jsonArr[0];
            Assert.IsTrue(jsonBoolean);

            Assert.IsTrue(jsonArr[1] is bool);
            jsonBoolean = (bool)jsonArr[1];
            Assert.IsFalse(jsonBoolean);

            Assert.IsNull(jsonArr[2]);
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseHybridArray()
        {
            string jsonStr = @"[""\t\r\n\\\b\f\/""  ,  ""\u8896""  ,   123e-1  ,  true  ,  false,  null,  {}  ,  {""name"":123}]";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONArray);
            var jsonArr = json as JSONArray;
            Assert.IsTrue(jsonArr != null && jsonArr.Count == 8);
            Assert.IsTrue(jsonArr[0] is string);
            string jsonString = (string)jsonArr[0];
            Assert.AreEqual("\t\r\n\\\b\f/", jsonString);

            Assert.IsTrue(jsonArr[1] is string);
            jsonString = (string)jsonArr[1];
            Assert.AreEqual("袖", jsonString);

            Assert.IsTrue(jsonArr[2] is double);
            var jsonNumber = (double)jsonArr[2];
            Assert.AreEqual(12.3, jsonNumber);

            Assert.IsTrue(jsonArr[3] is bool);
            bool jsonBoolean = (bool)jsonArr[3];
            Assert.IsTrue(jsonBoolean);

            Assert.IsTrue(jsonArr[4] is bool);
            jsonBoolean = (bool)jsonArr[4];
            Assert.IsFalse(jsonBoolean);

            Assert.IsNull(jsonArr[5]);

            Assert.IsTrue(jsonArr[6] is JSONObject);
            var jsonObj = jsonArr[6] as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 0);

            Assert.IsTrue(jsonArr[7] is JSONObject);
            jsonObj = jsonArr[7] as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 1);
            Assert.AreEqual(123, (double)jsonObj["name"]);
        }
        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseObject()
        {
            string jsonStr = "{\"name\":\"value\"}";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONObject);
            var jsonObj = json as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 1);
            Assert.IsTrue(jsonObj.ContainsKey("name"));
            Assert.AreEqual("value", (string)jsonObj["name"]);

            jsonStr = "{ \"name\" \t:  123e-1  }  ";
            json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONObject);
            jsonObj = json as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 1);
            Assert.IsTrue(jsonObj.ContainsKey("name"));
            Assert.AreEqual(12.3, (double)jsonObj["name"]);

            jsonStr = "{\"name0\":\"value\", \"name1\" \t:  123e-1  }  ";
            json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONObject);
            jsonObj = json as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 2);
            Assert.IsTrue(jsonObj.ContainsKey("name0"));
            Assert.AreEqual("value", (string)jsonObj["name0"]);

            Assert.IsTrue(jsonObj.ContainsKey("name1"));
            Assert.AreEqual(12.3, (double)jsonObj["name1"]);
        }

        [TestMethod]
        [TestCategory(catetory)]
        public void TestParseObjectAndArray()
        {
            string jsonStr = @"[""\t"",{
                                        ""name"":123,
                                        ""array"":[{
                                            ""name"":{
                                                ""name"":true
                                            }}]
                                        }]";
            var json = JSON.Parse(jsonStr);
            Assert.IsTrue(json is JSONArray);
            var jsonArr = json as JSONArray;
            Assert.IsTrue(jsonArr != null && jsonArr.Count == 2);
            Assert.IsTrue(jsonArr[0] is string);
            string jsonString = (string)jsonArr[0];
            Assert.AreEqual("\t", jsonString);

            Assert.IsTrue(jsonArr[1] is JSONObject);
            var jsonObj = jsonArr[1] as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 2);
            Assert.AreEqual(123, (double)jsonObj["name"]);
            Assert.IsTrue(jsonObj["array"] is JSONArray);
            jsonArr = jsonObj["array"] as JSONArray;
            Assert.IsTrue(jsonArr != null && jsonArr.Count == 1);
            Assert.IsTrue(jsonArr[0] is JSONObject);
            jsonObj = jsonArr[0] as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 1);
            Assert.IsTrue(jsonObj["name"] is JSONObject);
            jsonObj = jsonObj["name"] as JSONObject;
            Assert.IsTrue(jsonObj != null && jsonObj.Count == 1);
            Assert.IsTrue((bool)jsonObj["name"]);

        }
        [TestMethod]
        [TestCategory(catetory)]
        [ExpectedException(typeof(Exception))]
        public void TestParseMalformedText()
        {
            string jsonStr = @" [";
            var json = JSON.Parse(jsonStr);
        }
    }
}
